<?php
/**
 * The Thread class which can be used to implement multithreading up to some
 * reasonable extent
 **/
abstract class Thread {

    /**
     * @var Guid Thread identifier
     **/
    private $_id;

    /**
     * @var Boolean A flag indicating that the thread is currently
     * in the running state
     **/
    private $_running = false;

    /**
     * @var int Keeps the value how many iterations the thread has made
     **/
    private $_ticks = 0;

    /**
     * @return int Whether the given thread is in the running state
     **/
    public function running() {
        return $this->_running;
    }

    public function getTickCount() {
        return $this->_ticks;
    }

    /**
     * Builds the thread file name
     * @param Guid $id The thread identifier
     * @return String Resulting file name
     **/
    public function buildThreadFileName($id = null) {
        if (null == $id) {
            $id = $this->_id;
        }

        return "Framework.Threading.Thread." . $id->toString();
    }

    /**
     * Starts the thread.
     * Thread is first attempted to restore and a new thread is created if
     * restore is not possible.
     **/
    public function start() {

        if ($this->restore()) {
            return;
        }

        // Create thread identifier
        $this->_id = new Guid();

        // Create thread file
        $file = fopen($this->buildThreadFileName(), "a+");
        if ($file) {

            // Set the running state to true
            $this->_running = true;

            fclose($file);
        }

        $this->iterate();
    }

    /**
     * Stops the thread.
     * Intended to be called from the thread routine
     **/
    public function stop() {
        $this->_running = false;
    }

    /**
     * Back-ups the thread by saving thread data to the thread file.
     **/
    public function backup() {
        if (!file_exists($this->buildThreadFileName())) {
            $this->_running = false;
        }

        // Render any output
        // That may be required for outer thread execution control
        flush();
    }

    /**
     * Thread iteration loop
     **/
    public function iterate() {
        while ($this->_running) {
            ++$this->_ticks;
            $this->process();
            $this->backup();
        }
    }

    /**
     * Thread action.
     * This method is called for each thread iteration.
     **/
    public abstract function process();

    /**
     * Restores the thread if possible
     * @return boolean A value indicating whether the thread was restored or not
     **/
    public function restore() {
        if (isset($_REQUEST['Framework_Threading_Thread_id'])) {
            $id = new Guid($_REQUEST['Framework_Threading_Thread_id']);
            if (is_file($this->buildThreadFileName($id))) {
                $this->_id = $id;
                $this->_running = true;
                $this->iterate();
                return true;
            }
        }

        return false;
    }
}
?>